/**********************************************************************

Filename    :   FxGameDelegate.h
Content     :   External Interface callback registration mechanism
Created     :
Authors     :   Prasad Silva

Copyright   :   (c) 2005-2009 Scaleform Corp. All Rights Reserved.

This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.

**********************************************************************/

#ifndef INC_FxGameDelegateHandler_H
#define INC_FxGameDelegateHandler_H

#include "GFxPlayer.h"
#include "GMemory.h"

class FxDelegate;
class FxDelegateArgs;


//
// Interface implemented by all callback handlers. These handlers register 
// callbacks with the FxGameDelegate.
//

//
// All callback methods must have the following signature. To produce a response
// to the callback, push parameters to the game delegate.
//
typedef void (*CallbackFn)(const FxDelegateArgs& params);    

//
// Special handler callback signature to listen for all methods.
//
typedef void (*FallbackFn)(const FxDelegateArgs& params, const char* methodName);

//
// Interface implemented by callback registrars. The handler should 
// pass the appropriate parameters to the Visit method.
//
class CallbackProcessor
{
public:
	virtual ~CallbackProcessor() {}
	virtual void    Process(const GString& methodName, CallbackFn method) = 0;
};

class FxDelegateHandler /*: public GRefCountBase<FxDelegateHandler, GStat_Default_Mem>*/
{
public:
    virtual ~FxDelegateHandler() {}
    //
    // Callback registrar visitor method
    // Implementations are expected to call the registrar's Process method
    // for all callbacks.
    //
    virtual void      Accept(CallbackProcessor* cbreg) = 0;
};


//////////////////////////////////////////////////////////////////////////


//
// Parameters passed to the callback handler
//
class FxDelegateArgs
{
public:
    FxDelegateArgs(FxDelegateHandler* pthis, GFxMovieView* pmovie, const GFxValue* vals, UInt nargs) 
                   : pThis(pthis), pMovieView(pmovie), Args(vals), NArgs(nargs) {}

    FxDelegateHandler*  GetHandler() const      { return pThis; }
    GFxMovieView*       GetMovie() const        { return pMovieView; }

    const GFxValue&     operator[](UPInt i) const
    { 
        GASSERT(i < NArgs);
        return Args[i]; 
    }
    UInt                GetArgCount() const     { return NArgs; }

private:
    FxDelegateHandler*      pThis;
    GFxMovieView*           pMovieView;
    const GFxValue*         Args;
    UInt                    NArgs;
};


//////////////////////////////////////////////////////////////////////////

//
// Callback target
//
struct CallbackDefn
{
	FxDelegateHandler*	pThis;
	CallbackFn   pCallback;
};

// Fallback target
struct FallbackDefn
{
	FxDelegateHandler*	pThis;
	FallbackFn   pCallback;
};

//
// Callback hash
//
struct CallbackHashFunctor
{
	UPInt  operator()(const char* data) const
	{
		UPInt  size = G_strlen(data);
		return GString::BernsteinHashFunction(data, size);
	}
};
typedef GHash<GString, CallbackDefn, CallbackHashFunctor> CallbackHash;

class AddCallbackVisitor : public CallbackProcessor
{
public:
	AddCallbackVisitor(FxDelegateHandler* pthis, CallbackHash* phash)
		: pThis(pthis), pHash(phash) {}

	void Process(const GString& methodName, CallbackFn method)
	{
		CallbackDefn cbt;
		cbt.pThis = pThis;
		cbt.pCallback = method;
		pHash->Add(methodName, cbt);
	}

private:
	FxDelegateHandler*          pThis;
	CallbackHash*   pHash;
};


//
// Visitor to unregister callbacks
//
class RemoveCallbackVisitor : public CallbackProcessor
{
public:
	RemoveCallbackVisitor(FxDelegateHandler* pthis, CallbackHash* phash)
		: pThis(pthis), pHash(phash) {}

	void Process(const GString& methodName, CallbackFn method)
	{
		GUNUSED(method);
		pHash->Remove(methodName);
	}

private:
	FxDelegateHandler*          pThis;
	CallbackHash*   pHash;
};


#endif // INC_FxGameDelegateHandler_H
